package com.ning.parking.service.impl;

import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ning.parking.domain.ParkingLotMonthlyApply;
import com.ning.parking.domain.ParkingLotWhitelist;
import com.ning.parking.domain.ParkingRecord;
import com.ning.parking.domain.VO.BillingTimeVO;
import com.ning.parking.domain.VO.Pagination;
import com.ning.parking.domain.dto.*;
import com.ning.parking.service.ParkingLotMonthlyApplyService;
import com.ning.parking.mapper.ParkingLotMonthlyApplyMapper;
import com.scsonic.common.enums.StatusEnum;
import com.scsonic.common.enums.monthly.*;
import com.scsonic.common.enums.parking.ParkingCarTypeEnum;
import com.scsonic.common.utils.BeanUtils;
import com.scsonic.framework.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 *
 */
@Service
@Slf4j
public class ParkingLotMonthlyApplyServiceImpl extends ServiceImpl<ParkingLotMonthlyApplyMapper, ParkingLotMonthlyApply>
    implements ParkingLotMonthlyApplyService{

    @Autowired
    private ParkingLotMonthlyRuleService parkingLotMonthlyRuleService;

    @Autowired
    private ParkingLotMonthlyApplyCarService parkingLotMonthlyApplyCarService;

    @Autowired
    private ParkingLotMonthlyApplyProveService parkingLotMonthlyApplyProveService;
    @Autowired
    private ParkingLotMonthlyApplyAuditRecordProveService parkingLotMonthlyApplyAuditRecordProveService;

    /**
     * --------------------------------
     * @param applyEntity
     * @param applyCarList
     * @param baseProveList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Long saveApplyInfo(ParkingLotMonthlyApplyPageDto applyEntity, List<ParkingLotMonthlyApplyCarDTO> applyCarList, List<ParkingLotMonthlyApplyProveDTO> baseProveList) {
        ParkingLotMonthlyRuleEntity ruleEntity = parkingLotMonthlyRuleService.getById(applyEntity.getMonthlyRuleId());
        if (applyEntity.getApplyType() == MonthlyApplyTypeEnum.NEW_APPLY) {

            //是否审核，资料存起来
            parkingLotMonthlyApplyCarService.saveApplyCarList(applyEntity.getMonthlyMainApplyId(), applyEntity.getParkingLotId(), applyCarList);

            // 保存基本资料
            parkingLotMonthlyApplyProveService.saveApplyProveList(applyEntity.getMonthlyMainApplyId(), BeanUtils.copyToList(baseProveList, ParkingLotMonthlyApplyProveEntity.class), MonthlyApplyProveTypeEnum.BASE);
        }
        // 后台办理不需要审核
        boolean backNoAuditFlag = applyEntity.getApplyType() == MonthlyApplyTypeEnum.RE_NEW ? Boolean.TRUE : applyEntity.getDataSource() == MonthlyDataSourceEnum.BACKSTAGE && (ruleEntity.getAuditFlag() == StatusEnum.NO );
        // 小程序办理不需要审核
        boolean appletNoAuditFlag = applyEntity.getApplyType() == MonthlyApplyTypeEnum.RE_NEW ? Boolean.TRUE : applyEntity.getDataSource() == MonthlyDataSourceEnum.APPLET && (ruleEntity.getAuditFlag() == StatusEnum.NO ||
                ruleEntity.getAppletAuditFlag() == StatusEnum.NO);
        if (backNoAuditFlag || appletNoAuditFlag) {
            // 免审核申请单的处理
            applyEntity.setAuditStatus(MonthlyAuditStatusEnum.NOT_NEED_AUDIT);
            applyEntity.setMonthlyStatus(MonthlyStatusEnum.PROCESSING);
            applyEntity.setApplyStatus(MonthlyApplyStatusEnum.NEED_TO_PAY);
            applyEntity.setOrderStatus(MonthlyOrderStatusEnum.NEED_TO_PAY);
            //updateById(applyEntity);
            // 0 元订单
            if (applyEntity.getPayableAmount().compareTo(BigDecimal.ZERO) == 0) {
                zeroOrder(applyEntity, MonthlyAuditStatusEnum.NOT_NEED_AUDIT);
            }
            return applyEntity.getMonthlyId();
        }
        //审核
        //免审核，免审核，直接生成一条审核通过记录
        //Long auditRecordId = parkingLotMonthlyApplyAuditRecordService.saveRecord(ParkingLotMonthlyApplyAuditRecordDTO.builder().monthlyMainApplyId(applyEntity.getMonthlyMainApplyId()).monthlyApplyId(applyEntity.getId()).monthlyRuleId(applyEntity.getMonthlyRuleId()).auditType(MonthlyAuditTypeEnum.NEW_APPLY).auditStatus(StatusEnum.NO).build(), Boolean.FALSE);

        parkingLotMonthlyApplyAuditRecordProveService.saveMonthlyProve(applyEntity.getMonthlyId(), null, baseProveList, applyCarList);
        return applyEntity.getMonthlyId();
    }

    private void zeroOrder(ParkingLotMonthlyApplyPageDto applyEntity, MonthlyAuditStatusEnum notNeedAudit) {
        this.baseMapper.saveZeroder(applyEntity);
    }

    @Override
    public Pagination<ParkingLotMonthlyApply> selectPage(ParkingLotMonthlyApplyPageDto pageBase) {
        //小于 大于
        Page<ParkingLotMonthlyApply> page = lambdaQuery()
                .like(ObjectUtil.isNotEmpty(pageBase.getCarLicense()), ParkingLotMonthlyApply::getCarLicense, pageBase.getCarLicense())
                .orderByDesc(ParkingLotMonthlyApply::getMonthlyId).page(pageBase.toPage());
        return Pagination.of(page);
    }

    @Override
    public ParkingLotMonthlyApply selectMonthlyExit(String carLicense, Date captureTime, Long parkingLotId) {
        List<ParkingLotMonthlyApply> monthlyApplyList =  this.baseMapper.selectMonthly(carLicense,captureTime,parkingLotId);
        if (ObjectUtil.isEmpty(monthlyApplyList)){
            return null;
        }
        return monthlyApplyList.get(0);
    }

    @Override
    public ParkingLotMonthlyApply selectMonthly(String carLicense, Date captureTime,Long parkingLotId) {
        ParkingLotMonthlyApply one = lambdaQuery()
                .eq(ParkingLotMonthlyApply::getCarLicense, carLicense)
                .eq(ParkingLotMonthlyApply::getParkingLotId, parkingLotId)
//                .gt(ParkingLotMonthlyApply::getMonthlyStatus, MonthlyStatusEnum.IN_EFFECT.getValue())
                .le(ParkingLotMonthlyApply::getMonthlyStartDay, captureTime)
                .ge(ParkingLotMonthlyApply::getMonthlyEndDay, captureTime)
                .last("limit 1")
                .one();
        if (one==null){
            return one;
        }


        Date startTime = one.getMonthlyStartDay();

        Date endTime = one.getMonthlyEndDay();

        captureTime = DateUtils.parseDate(DateUtils.formatDate(captureTime));

        if (startTime==null||endTime==null){
            return null;
        }

        if (startTime.getTime() <= captureTime.getTime() && endTime.getTime() >= captureTime.getTime()) {
            return one;
        }

        return null;
    }

    @Override
    public void saveBatchs(List<ParkingLotWhitelistCarLicenseEntity> licenseEntities) {

    }

    @Override
    public BillingTimeVO selectMonthlyRecord(ParkingRecord record) {
        DateTime exitTimeYMH =  DateUtils.date(new Date(record.getExitTime().getTime()));
        exitTimeYMH.setField(DateField.MILLISECOND,0);
        exitTimeYMH.setField(DateField.SECOND,0);
        exitTimeYMH.setField(DateField.HOUR_OF_DAY,0);
        exitTimeYMH.setField(DateField.MINUTE,0);
        List<ParkingLotMonthlyApply> monthlyApplyList =  this.baseMapper.selectMonthlyApplys(record.getCarLicense(),record.getEntTime(),record.getParkingLotId());

//        List<ParkingLotMonthlyApply> monthlyApplyList = lambdaQuery()
//                .eq(ParkingLotMonthlyApply::getCarLicense, record.getCarLicense())
//                .gt(ParkingLotMonthlyApply::getMonthlyStartDay, record.getEntTime())
//                .orderByDesc(ParkingLotMonthlyApply::getMonthlyStartDay)
//                .list();

        BillingTimeVO billingTimeVO = new BillingTimeVO();
        if (ObjectUtil.isEmpty(monthlyApplyList)) {
            billingTimeVO.setEntTime(record.getEntTime());
            billingTimeVO.setExitTime(record.getExitTime());
            billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
            return billingTimeVO;
        }

        Date monthlyEndDay = monthlyApplyList.get(0).getMonthlyEndDay();
        Date startDay = monthlyApplyList.get(0).getMonthlyStartDay();

        //月租完全包含
        if (monthlyEndDay.getTime()>=exitTimeYMH.getTime()  && startDay.getTime() <= record.getEntTime().getTime() ){
            record.setLedShow(record.getCarLicense()+"月租车辆祝您一路顺风");
            billingTimeVO.setParkingCarType(ParkingCarTypeEnum.MONTHLY);
            return billingTimeVO;
        }

        //月租超停
        if (monthlyApplyList.size() == 1){

            if (startDay.getTime() < exitTimeYMH.getTime()){

                DateTime endDay = DateUtils.date(monthlyEndDay);
                //结束时间是从00点-24 需要增加一天
                endDay.setField(DateField.DAY_OF_YEAR,endDay.getField(DateField.DAY_OF_YEAR)+1);
                Long exitMs = record.getExitTime().getTime() - endDay.getTime();
                log.info("总-超停时长:{}", DateUtil.formatBetween(record.getExitTime(), endDay, BetweenFormatter.Level.SECOND));
                record.setRemark("超停时长"+DateUtil.formatBetween(record.getExitTime(), endDay, BetweenFormatter.Level.SECOND));
                Date exitTime = new Date(record.getEntTime().getTime() + exitMs);
                billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
                billingTimeVO.setEntTime(record.getEntTime());
                billingTimeVO.setExitTime(exitTime);
                return billingTimeVO;
            }else {
                long exitMs = startDay.getTime() - exitTimeYMH.getTime();
                Date exitTime = new Date(record.getEntTime().getTime() + exitMs);
                billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
                billingTimeVO.setEntTime(record.getEntTime());
                billingTimeVO.setExitTime(exitTime);
                return billingTimeVO;
            }

        }

        //多次续租累积后
        Long exitMs = 0L;
        //必须少循环一层不然会出数组越界 稳妥起见循环之后处理最后一次
        for (int i = 0; i < monthlyApplyList.size()-1; i++) {
            ParkingLotMonthlyApply parkingLotMonthlyApplyAf = monthlyApplyList.get(i);
            //开始时间比较
            if (i==0){
                Date start = parkingLotMonthlyApplyAf.getMonthlyStartDay();
                Date entTime = record.getEntTime();
                if (entTime.getTime() < start.getTime()) {
                    log.info("超停时长:{}", DateUtil.formatBetween(start, entTime, BetweenFormatter.Level.SECOND));
                    record.setRemark("超停时长"+DateUtil.formatBetween(start, entTime, BetweenFormatter.Level.SECOND));
                    exitMs += start.getTime() - entTime.getTime();
                }
            }

            DateTime endDay = DateUtils.date(parkingLotMonthlyApplyAf.getMonthlyEndDay());
            //结束时间是从00点-24 需要增加一天
            endDay.setField(DateField.DAY_OF_YEAR,endDay.getField(DateField.DAY_OF_YEAR)+1);
            long exitPoor = record.getExitTime().getTime() - endDay.getTime();

            //月租结束大于出场结束
            if (exitPoor < 0){
                billingTimeVO.setEntTime(record.getEntTime());
                if (exitMs<=0) {
                    record.setLedShow(record.getCarLicense()+"月租车辆祝您一路顺风");
                    billingTimeVO.setParkingCarType(ParkingCarTypeEnum.MONTHLY);
                    return billingTimeVO;
                }
                billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
                Date exitTime = new Date(record.getEntTime().getTime() + exitMs);
                billingTimeVO.setExitTime(exitTime);
                log.info("总-超停时长:{}", DateUtil.formatBetween(exitTime, record.getEntTime(), BetweenFormatter.Level.SECOND));
                record.setRemark("超停时长"+DateUtil.formatBetween(exitTime, record.getEntTime(), BetweenFormatter.Level.SECOND));
                return billingTimeVO;
            }

            ParkingLotMonthlyApply parkingLotMonthlyApplyBe = monthlyApplyList.get(i+1);
            DateTime endDayAf = DateUtils.date( parkingLotMonthlyApplyAf.getMonthlyEndDay());
            DateTime startDayBe = DateUtils.date( parkingLotMonthlyApplyBe.getMonthlyStartDay());
            //结束时间是从00点-24 需要增加一天
            endDayAf.setField(DateField.DAY_OF_YEAR,endDayAf.getField(DateField.DAY_OF_YEAR)+1);
            long poor = startDayBe.getTime() -endDayAf.getTime();
            if (poor > 0) {
                log.info("超停时长:{}", DateUtil.formatBetween(endDayAf, startDayBe, BetweenFormatter.Level.SECOND));
                record.setRemark("超停时长"+DateUtil.formatBetween(endDayAf, startDayBe, BetweenFormatter.Level.SECOND));
                exitMs =+ poor;
            }
        }

        ParkingLotMonthlyApply parkingLotMonthlyApply = monthlyApplyList.get(monthlyApplyList.size() - 1);
        DateTime endDay = DateUtils.date( parkingLotMonthlyApply.getMonthlyEndDay());
        //结束时间是从00点-24需要增加一天
        endDay.setField(DateField.DAY_OF_YEAR,endDay.getField(DateField.DAY_OF_YEAR)+1);
        long poor = record.getExitTime().getTime() - endDay.getTime();
        if (poor > 0) {
            log.info("超停时长:{}", DateUtil.formatBetween(record.getExitTime(), endDay, BetweenFormatter.Level.SECOND));
            record.setRemark("超停时长"+DateUtil.formatBetween(record.getExitTime(), endDay, BetweenFormatter.Level.SECOND));
            exitMs += poor;
        }
        Date exitTime = new Date(record.getEntTime().getTime() + exitMs);
        log.info("总-超停时长:{}", DateUtil.formatBetween(exitTime, record.getEntTime(), BetweenFormatter.Level.SECOND));
        record.setRemark("超停时长"+DateUtil.formatBetween(exitTime, record.getEntTime(), BetweenFormatter.Level.SECOND));
        billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
        billingTimeVO.setEntTime(record.getEntTime());
        billingTimeVO.setExitTime(exitTime);
        return billingTimeVO;
    }
}




